package org.JWCB.job.handler;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.JWCB.common.core.constants.CacheConstants;
import org.JWCB.common.core.constants.MessageConstants;
import org.JWCB.common.core.constants.UserConstants;
import org.JWCB.common.core.enums.ExamStatus;
import org.JWCB.common.redis.service.RedisService;
import org.JWCB.job.domain.exam.Exam;
import org.JWCB.job.domain.message.entity.Message;
import org.JWCB.job.domain.message.entity.MessageText;
import org.JWCB.job.domain.message.vo.MessageTextVo;
import org.JWCB.job.domain.user.UserScore;
import org.JWCB.job.mapper.exam.ExamMapper;
import org.JWCB.job.mapper.user.UserExamMapper;
import org.JWCB.job.mapper.user.UserSubmitMapper;
import org.JWCB.job.service.MessageService;
import org.JWCB.job.service.MessageTextService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class ExamXxlJobHandler {


    @Autowired
    private ExamMapper examMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserSubmitMapper userSubmitMapper;


    @Autowired
    private MessageTextService messageTextService;

    @Autowired
    private MessageService messageService;
    @Autowired
    private UserExamMapper userExamMapper;

    /**
     * 刷新缓存(将完赛竞赛列表放入历史列表)
     */
    @XxlJob("examListOrganizeHandler")
    public void examListOrganizeHandler() {
        try {
            log.info("************{}xxl_job刷新缓存***********",LocalDateTime.now());
            List<Exam> unFinishList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                    .select(Exam::getExamId,Exam::getTitle,Exam::getStartTime,Exam::getEndTime)
                    .gt(Exam::getEndTime, LocalDateTime.now())
                    .eq(Exam::getStatus, ExamStatus.PUBLISHED.getCode())
                    .orderByDesc(Exam::getStartTime));
            refreshCache(CacheConstants.EXAM_UNFINISHED_LIST_KEY,unFinishList);
            List<Exam> historyList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                    .select(Exam::getExamId,Exam::getTitle,Exam::getStartTime,Exam::getEndTime)
                    .le(Exam::getEndTime, LocalDateTime.now())
                    .eq(Exam::getStatus, ExamStatus.PUBLISHED.getCode())
                    .orderByDesc(Exam::getStartTime));
            refreshCache(CacheConstants.EXAM_HISTORY_LIST_KEY,historyList);
        }catch (Exception e) {
            throw new RuntimeException();
        }
    }


    @XxlJob("examResultHandler")
    public void  examResultHandler() {
        log.info("************{}xxl_job统计信息***********",LocalDateTime.now());

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime minusDateTime = now.minusDays(1);
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId,Exam::getTitle)
                .eq(Exam::getStatus,ExamStatus.PUBLISHED.getCode())
                .ge(Exam::getEndTime,minusDateTime)
                .le(Exam::getEndTime,now));
        if(CollectionUtil.isEmpty(examList)) {
            return;
        }
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());
        List<UserScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet);
        Map<Long, List<UserScore>> userScoreMap = userScoreList.stream().collect(Collectors.groupingBy(UserScore::getExamId));
        createExamResMessage(examList,userScoreMap);
    }

    /**
     * 创建消息
     */
    private void createExamResMessage(List<Exam> examList,Map<Long, List<UserScore>> userScoreMap) {
        List<MessageText> messageTextList = new ArrayList<>();
        List<Message> messageList = new ArrayList<>();
        for(Exam exam : examList) {
            Long examId = exam.getExamId();
            List<UserScore> userScoreList = userScoreMap.get(examId);
            int userCount = userScoreList.size();
            int rank = 1;
            for(UserScore userScore : userScoreList) {
                String messageTitle = exam.getTitle() + MessageConstants.EXAM_RES_MESSAGE_TITLE;
                String messageContent = String.format(MessageConstants.EXAM_RES_MESSAGE_CONTENT, exam.getTitle(), userCount, rank);
                userScore.setExamRank(rank);
                MessageText messageText = createMessageText(messageTitle,messageContent);
                messageTextList.add(messageText);
                Message message = createMessage(userScore.getUserId());
                messageList.add(message);
                rank++;
            }
            // 将竞赛信息同步到数据库
            insertToDB(userScoreList, examId);
        }
        messageTextService.batchSave(messageTextList);
        Map<String, MessageTextVo> messageTextVoMap = new HashMap<>();
        for (int i = 0; i < messageTextList.size(); i++) {
            MessageText messageText = messageTextList.get(i);
            Long textId = messageText.getTextId();
            messageList.get(i).setTextId(textId);
            MessageTextVo messageTextVo = new MessageTextVo();
            BeanUtil.copyProperties(messageText,messageTextVo);
            messageTextVoMap.put(getMessageDetailKey(textId),messageTextVo);
        }
        messageService.batchSave(messageList);
        Map<Long, List<Message>> userMessageMap = messageList.stream().collect(Collectors.groupingBy(Message::getAcceptorId));
        insertMsgToCache(userMessageMap);
        redisService.multiSet(messageTextVoMap);
    }

    private void insertToDB(List<UserScore> userScoreList, Long examId) {
        userExamMapper.updateUserExamInfo(userScoreList);
        String userExamLinkListKey = getUserExamLinkListKey(examId);
        Long listSize = redisService.getListSize(userExamLinkListKey);
        if(listSize == 1) {
            // 缓存是否为空
            List<UserScore> userScores = redisService.getCacheListByRange(userExamLinkListKey, 0, 1, UserScore.class);
            if(userScores.get(0).getExamId() == -1) {
                redisService.deleteObject(userExamLinkListKey);
            }
        }
        redisService.rightPushAll(userExamLinkListKey,userScoreList);
    }


    /**
     * 获取text实体
     * @param messageTile 标题
     * @param messageContent 内容
     */
    private MessageText createMessageText(String messageTile,String messageContent) {
        MessageText messageText = new MessageText();
        messageText.setMessageTitle(messageTile);
        messageText.setMessageContent(messageContent);
        messageText.setCreateBy(UserConstants.SYSTEM_USER_ID);
        messageText.setUpdateBy(UserConstants.SYSTEM_USER_ID);
        messageText.setCreateTime(LocalDateTime.now());
        messageText.setUpdateTime(LocalDateTime.now());
        return messageText;
    }


    /**
     * message实体
     * @param acceptorId 接收方
     */
    private Message createMessage(Long acceptorId) {
        Message message = new Message();
        message.setSenderId(UserConstants.SYSTEM_USER_ID);
        message.setAcceptorId(acceptorId);
        message.setCreateBy(UserConstants.SYSTEM_USER_ID);
        message.setUpdateBy(UserConstants.SYSTEM_USER_ID);
        return message;
    }


    /**
     * 将消息列表数据插入缓存
     */
    private void insertMsgToCache(Map<Long, List<Message>> userMessageMap) {
        for (Map.Entry<Long, List<Message>> entry : userMessageMap.entrySet()) {
            String userMessageListKey = getUserMessageListKey(entry.getKey());
            List<Long> ids = redisService.getCacheListByRange(userMessageListKey, 0, -1, Long.class);
            if(ids != null && ids.size() == 1 && ids.get(0) == -1) {
                // 清除设置的空值
                redisService.deleteObject(userMessageListKey);
            }

            List<Message> messageList = entry.getValue();
            Set<Long> textIds = messageList.stream().map(Message::getTextId).collect(Collectors.toSet());
            redisService.rightPushAll(userMessageListKey, textIds);
        }
    }
    /**
     * 刷新缓存
     * @param examListKey 缓存key
     * @param examList 竞赛列表
     */
    private void refreshCache(String examListKey,List<Exam> examList) {
        if(CollectionUtil.isEmpty(examList)) {
            redisService.deleteObject(examListKey);
            return;
        }
        Map<String,Exam> examMap = new HashMap<>();
        List<Long> examIds = new ArrayList<>();
        for(Exam exam : examList) {
            examMap.put(getDetailKey(exam.getExamId()),exam);
            examIds.add(exam.getExamId());
        }
        redisService.multiSet(examMap);
        redisService.deleteObject(examListKey);
        redisService.rightPushAll(examListKey,examIds);
    }

    /**
     * 获取缓存中examDetail的key
     * @param examId 竞赛id
     * @return key
     */
    private String getDetailKey(Long examId) {
        return CacheConstants.EXAM_DETAIL_KEY + examId;
    }



    private String getUserMessageListKey(Long userId) {
        return CacheConstants.USER_MESSAGE_LIST_KEY + userId;
    }

    private String getMessageDetailKey(Long textId) {
        return  CacheConstants.MESSAGE_DETAIL_KEY + textId;
    }


    private String getUserExamLinkListKey(Long examId) {
        return CacheConstants.EXAM_RANK_LIST_KEY + examId;
    }

}
